﻿
// Copyright © 2009 Mehdi Golchin. All rights reserved.

namespace TinyMceWrapper
{

    #region [ Imports ]

    using System;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.Configuration;
    using System.Drawing;
    using System.Drawing.Design;
    using System.Text;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using TinyMceWrapper.Design;
    using TinyMceWrapper.Configuration;

    #endregion

    [ToolboxData("<{0}:TinyMce runat=\"server\" />"), DefaultProperty("Text"), DefaultEvent("TextChanged"), Designer(typeof(TinyMceDesigner))]
    [ValidationProperty("Text"), ControlBuilder(typeof(TinyMceControlBuilder)), ParseChildren(true, "Text"), ToolboxBitmap(typeof(TinyMce))]
    public class TinyMce : WebControl, IPostBackDataHandler, IEditableTextControl, ITextControl
    {

        #region [ Local Fields ]

        private static readonly object _textChangedEvent = new object();

        #endregion

        #region [ Constructors ]

        public TinyMce() : base(HtmlTextWriterTag.Textarea) { }

        #endregion

        #region [ Public Virtual Properties ]

        [Category("Behavior"), DefaultValue(-1)]
        public virtual int Rows
        {
            get { return base.ViewState.GetValue("Rows", -1); }
            set { base.ViewState.SetValue("Rows", value); }
        }

        [Category("Behavior"), DefaultValue(-1)]
        public virtual int Columns
        {
            get { return base.ViewState.GetValue("Columns", -1); }
            set { base.ViewState.SetValue("Columns", value); }
        }

        [Category("Behavior"), DefaultValue("Simple")]
        public virtual string DisplayMode
        {
            get { return base.ViewState.GetValue("DisplayMode", "Simple"); }
            set
            {
                Utilities.NotNullOrEmpty(value, "value");
                base.ViewState.SetValue("DisplayMode", value);
            }
        }

        #endregion

        #region [ Protected Virtual Methods ]

        protected virtual void OnTextChanged(EventArgs e)
        {
            EventHandler handler = (EventHandler)base.Events[_textChangedEvent];
            if (handler != null) handler(this, e);
        }

        #endregion

        #region [ Overriden Members ]

        protected override void OnPreRender(EventArgs e)
        {
            if (!base.DesignMode && this.Page != null)
            {
                TinyMceSection section = ConfigurationManager.GetSection("tinymce") as TinyMceSection;
                TinyMceDisplayMode mode = null;
                string displayMode = this.DisplayMode;

                Utilities.ThrowException<ConfigurationErrorsException>(section == null, string.Format(SR.Configuration_unable_to_get_section, "tinymce"));

                if (section.DisplayModes != null)
                    mode = section.DisplayModes[displayMode];

                Utilities.ThrowException<HttpException>(mode == null, string.Format(SR.TinyMce_display_mode_not_found, displayMode));

                Page.ClientScript.RegisterClientScriptInclude(typeof(TinyMce), "TinyMCE", this.ResolveClientUrl(string.Format("{0}/tiny_mce{1}.js",
                    section.ScriptPath, !string.IsNullOrEmpty(section.ScriptMode) ? "_" + section.ScriptMode : null)));

                StringBuilder script = new StringBuilder();
                string[] options = new string[mode.Options.Count];
                int index = 0;

                script.AppendFormat("tinyMCE.init({{elements: '{0}', ", this.ClientID);

                foreach (TinyMceOption item in mode.Options)
                {
                    options[index] = string.Format("{0}: {1}", item.Key, (item.Value is string) ? "'" + (string)item.Value + "'" : item.Value.ToString().ToLower());
                    index++;
                }

                script.Append(string.Join(", ", options) + "});");

                Page.ClientScript.RegisterStartupScript(typeof(TinyMce), "TinyMCE_Init_" + this.ID, script.ToString(), true);
            }

            base.OnPreRender(e);
        }

        protected override void AddAttributesToRender(HtmlTextWriter writer)
        {
            base.AddAttributesToRender(writer);

            writer.AddAttribute(HtmlTextWriterAttribute.Name, this.UniqueID);
            if (this.Rows != -1) writer.AddAttribute(HtmlTextWriterAttribute.Rows, this.Rows.ToString());
            if (this.Columns != -1) writer.AddAttribute(HtmlTextWriterAttribute.Cols, this.Columns.ToString());
        }

        protected override void RenderContents(HtmlTextWriter writer)
        {
            base.RenderContents(writer);
            writer.Write(this.Text);
        }

        #endregion

        #region [ IPostBackDataHandler Members ]

        bool IPostBackDataHandler.LoadPostData(string postDataKey, NameValueCollection postCollection)
        {
            if (postDataKey == this.UniqueID)
            {
                string value = postCollection[postDataKey];
                if (this.Text != value)
                {
                    this.Text = value;
                    return true;
                }
            }
            return false;
        }

        void IPostBackDataHandler.RaisePostDataChangedEvent()
        {
            this.OnTextChanged(EventArgs.Empty);
        }

        #endregion

        #region [ IEditableTextControl Members ]

        [Category("Action")]
        public event EventHandler TextChanged
        {
            add { base.Events.AddHandler(_textChangedEvent, value); }
            remove { base.Events.RemoveHandler(_textChangedEvent, value); }
        }

        #endregion

        #region [ ITextControl Members ]

        [Category("Appearance"), DefaultValue(""), PersistenceMode(PersistenceMode.EncodedInnerDefaultProperty), Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))]
        public virtual string Text
        {
            get { return base.ViewState.GetValue("Text", string.Empty); }
            set { base.ViewState.SetValue("Text", value); }
        }

        #endregion

    }

}
